package com.zhangtai.filter;


import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSON;
import com.zhangtai.exception.DateUtils;
import com.zhangtai.exception.RException;
import com.zhangtai.utils.TokenDecode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: ming
 * @Date: 2020/2/7 0007 下午 1:21
 */
@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private RedisTemplate redisTemplate;




    private static final String AUTHORIZE_TOKEN = "MemberToken";



//
    private String accessUrl="/api-member/member/login,/api-member/member/QWLogin,api-member/member/getNotice";





    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {


        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();


        String s = request.getRemoteAddress().getAddress().toString();



//        获取当前请求,如果是登录请求则放行
        String path = request.getURI().getPath();
        log.info("请求路径是：{}",path);
        if (isAccess(path)){
            log.info("需要放行的请求路径是：{}",path);

            return chain.filter(exchange);
        }

//如果从请求头获取到token,且不过期，则放行
        String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);


        if (!StringUtils.isEmpty(token)&&token.contains("Bearer")&&token.length()>8){
            log.info("从请求头获取到了token: {}",token);


            //        如果过期或失效，返回状态码500
            if (isExpri(token)) {
                log.info("令牌失效");
                throw new RException("令牌失效了");

            }

//                        如果没过期，则判断是否即将过期，是的话重新刷新令牌过期时间生成新的令牌封装到请求头 RefreshToken
            isPreExpire(token);





           return chain.filter(exchange);

        }



//从请求头获取不到就从cookie中获取
        if (StringUtils.isEmpty(token)){

            token = getCookies(request);
            log.info("从cookies中获取到token:{}",token);
        }


        //如果cookie不存在令牌,则从请求参数中获取
        if (StringUtils.isEmpty(token)){
            token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
        }

//如果token获取不到,抛异常
        if (StringUtils.isEmpty(token)){
            log.info("没有获取到令牌");
            throw new RException("没有权限，请先登录");

        }


//        判断token是否过期，
        if (isExpri(token)){
        log.info("从cookie中获取的令牌失效了");
            throw new RException("令牌失效");
        }

//----------------------------------------------
//        如果token即将过期，则从新设置超时时间
        isPreExpire(token);







//        如果能从cookies获取到token，则添加到头信息


        log.info("开始设置请求头");
        ServerHttpRequest host = request.mutate().header(AUTHORIZE_TOKEN, "Bearer "+ token).build();
        ServerWebExchange build = exchange.mutate().request(host).build();
//        放行
        return chain.filter(build);

    }

//------------------------------------------------------------------------------------

    //    解析令牌是否过期
    private boolean isExpri(String token) {

        String bearer = token.replace("Bearer ", "");
        String decode = null;
        try {
            decode = TokenDecode.decode(bearer);
        } catch (Exception e) {
            log.info("令牌解析失败：{}",e.getMessage());
            return true;

        }

        Map<String,String> map = JSON.parseObject(decode, Map.class);
        String uuid = map.get("uuid");
//        log.info("uuid===========>>>>>>>:{}",uuid);

         Object o= redisTemplate.boundHashOps(uuid).get("login_item");
         if (ObjectUtils.isEmpty(o)){
             return true;
         }
        HashMap<String, Object> loginToken= (HashMap<String, Object>) o;
//        log.info("loginToken:{}",loginToken);
        Boolean flag = (Boolean) loginToken.get("flag");
//        如果登录标志为false,则返回登录失效
        if (!flag){
            return true;
        }
//      如果时间过期则返回登录失效
        Date expire = (Date) loginToken.get("expire");
        Date date = new Date();
        if (date.getTime()>=expire.getTime()){
            return true;
        }

        return false;
    }

    //判断是否还差两小时过期
    private void isPreExpire(String token) {

        String bearer = token.replace("Bearer ", "");
        String decode = TokenDecode.decode(bearer);


        Map<String,String> map = JSON.parseObject(decode, Map.class);
        String uuid = map.get("uuid");

         Object o=  redisTemplate.boundHashOps(uuid).get("login_item");
         if (ObjectUtils.isEmpty(o)){
             return;
         }
        HashMap<String, Object> loginToken= (HashMap<String, Object>) o;
        log.info("loginToken:{}",loginToken);
        Date expire = (Date) loginToken.get("expire");
//        Object expire1 = loginToken.get("expire");
//        log.info("expire:{}",expire1);
        Long date = new Date().getTime();
//        Date expire = new Date();
        Long bt=expire.getTime()-date;
//        log.info("时间差为:{}分钟",bt/1000/60);
        if (bt<=60*60*5){
            log.info("还差5分钟uuid失效:{}",uuid);
            Date newExp = DateUtils.addDateMinutes(new Date(), 30); //增加5分钟
            HashMap<String, Object> stringObjectHashMap = new HashMap<>();
            stringObjectHashMap.put("flag",true);
            stringObjectHashMap.put("expire",newExp);
            redisTemplate.boundHashOps(uuid).put("login_item",stringObjectHashMap);
            redisTemplate.expire(uuid,31, TimeUnit.MINUTES);
        }


    }







    //    判断是否解析成功解析token
    private Boolean IsdeCode(String token){

        String bearer = token.replace("Bearer ", "");
        String decode = null;
        try {
            decode = TokenDecode.decode(bearer);
        } catch (Exception e) {
            log.info("解析失败：{}",e.getMessage());
            return false;

        }
        return true;
    }



//    private Mono<Void> getVoidMono(String url, ServerHttpResponse response) {
//        response.setStatusCode(HttpStatus.SEE_OTHER);//303
//        //   跳转
//        response.getHeaders().add("Location",url);
//        return response.setComplete();
//    }

    private Boolean isAccess(String url){
        AntPathMatcher pathMatcher = new AntPathMatcher();
        String[] split = accessUrl.split(",");
//        System.out.println(split);
        for (String s : split) {


            if (pathMatcher.match(s,url)){

                return true;
            }
        }
        return false;
    }

//  获取cookies
    private String getCookies(ServerHttpRequest request) {

        HttpCookie cookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);
        if (cookie!=null){
            return cookie.getValue();
        }

        return null;
    }

//    public static void main(String[] args) {
//        Date date = new Date();
//        long time = date.getTime();
//        System.out.println(time);
//    }




    @Override
    public int getOrder() {
        return 0;
    }


}
